package IHM;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream.GetField;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import org.jdom.Element;

/**
 * Classe permettant l'affichage et la gestion des elements de l'arborescence 
 * @author Aubry Thomas
 * @author Bouchet Sylvain
 * @author Fauvel Alexis
 * @author Lessieur Jocelyn
 * @author Mathias Bastien 
 * @author Teuf Antoine
 * @version 1.0
 */

import Metier.Page;

/**
 * Classe permetant de generer et afficher l'arborescence
 * @author Aubry Thomas
 * @author Bouchet Sylvain
 * @author Fauvel Alexis
 * @author Lessieur Jocelyn
 * @author Mathias Bastien 
 * @author Teuf Antoine
 * @version 1.0
 */

public class Arborescence extends JTree implements TreeSelectionListener,MouseListener, ActionListener {

	/**
	 * Racine de l'arborescence
	 */
	private DefaultMutableTreeNode dmtn_racine;
	
	/**
	 * Arraylist des branches de l'arborescence
	 * @see Arborescence#getNoeud(String)
	 * @see Arborescence#getSelectedNoeud()
	 */
	private ArrayList<DefaultMutableTreeNode> dmtn_alTree; 
	
	/**
	 * Modele de l'arborescence
	 */
	private DefaultTreeModel dtm_model;
	
	/**
	 * IHM de l'application
	 */
	private IHM ihm;
	
	/**
	 * Item du menu suppprimer, ajouter, nouveau projet, Remonter la page, 
	 * descendre la page, copier, coller, couper, renomer
	 */
	private JMenuItem mi_supprimer,mi_ajoutPage,mi_newProjet,mi_prec,mi_suiv,
					  mi_copier,mi_coller,mi_couper,mi_renommer;
	
	/**
	 * Menu des popup
	 */
	private JPopupMenu popup,popup2;

	/**
	 * Constructeur de la classe Arborescence 
	 * @param ihm	la classe ihm
	 */
	public Arborescence(IHM ihm) {
		this.ihm = ihm;
		setPreferredSize(new Dimension(200, getHeight()));
		dmtn_racine = new DefaultMutableTreeNode("Mes projets"); // Construction
																	// de la
																	// racine		
		dmtn_alTree = new ArrayList<DefaultMutableTreeNode>();

		dtm_model = new DefaultTreeModel(dmtn_racine);
		setModel(dtm_model);
		addMouseListener(this);

		// Affichage de l'arbre
		DefaultTreeCellRenderer dtcr_renderer = new DefaultTreeCellRenderer();
		dtcr_renderer.setOpenIcon(null);
		dtcr_renderer.setClosedIcon(null);
		dtcr_renderer.setLeafIcon(null);
		setCellRenderer(dtcr_renderer);
		// setRootVisible(false);
		addTreeSelectionListener(this);
		
		
		
		//menupopup sur le reste de l'arborescence
		popup2 = new JPopupMenu();
		mi_newProjet = new JMenuItem("Nouveau Projet");
		mi_newProjet.addActionListener(this);
		popup2.add(mi_newProjet);
	}

	/**
	 * Permet d'ajouter une branche à un noeud
	 * @param nom	nom de la branche à ajouter
	 */
	public void ajouterFils(String nom) {
		ajouterFils(dmtn_racine.toString(), nom);
	}
	
	/**
	 * Permet d'ajouter une branche à un noeud
	 * @param nomPere	nom du pere du noeud
	 * @param nom		nom du fils à ajouter
	 */
	public void ajouterFils(String nomPere, String nom) {
		DefaultMutableTreeNode pere = getNoeud(nomPere);
		DefaultMutableTreeNode fils = new DefaultMutableTreeNode(nom);
		pere.add(fils);
		dmtn_alTree.add(fils);
		dtm_model = new DefaultTreeModel(dmtn_racine);
		setModel(dtm_model);
	}

	
	/**
	 * Permet de recuperer un noeud par son nom
	 * @param nom	nom du noeud à recuperer
	 * @return		le noeud dont le nom est passé en parametre
	 */
	public DefaultMutableTreeNode getNoeud(String nom) {
		if (dmtn_alTree.isEmpty()|| nom.equalsIgnoreCase(dmtn_racine.toString()))
			return dmtn_racine;
		else
			for (DefaultMutableTreeNode b : dmtn_alTree)
				if (b.toString().equals(nom))
					return b;
		return null;
	}

	// Méthodes pour changer de page et de projet à la selection de ces derniers
	// dans l'arbre
	/**
	 * Methodes permetant de changer de page et de projet lors de la selection 
	 * de ces dernier dans l'arborescence 
	 */
	public void valueChanged(TreeSelectionEvent e) {
		
		DefaultMutableTreeNode node = null;
		if(getSelectionPath() != null)
			node = (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
		
		if(node!=dmtn_racine){
			if(node.getParent()==dmtn_racine){
				ihm.getControleur().setProjetEnCours(ihm.getControleur().getProjetByNom(node.toString()));
				ihm.getMB().activerBoutons(true);
			}
			else{
				ihm.changerVisu(node.getParent().toString(), node.toString());
				ihm.getMB().activerBoutons(true);
			}
		}else{
			ihm.getMB().activerBoutons(false);
		}
			
	}

	@Override 
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		//menupopup sur les noeuds de l'arborescence
		popup = new JPopupMenu();
		mi_supprimer = new JMenuItem("Supprimer");
		mi_supprimer.addActionListener(this);
		mi_ajoutPage=new JMenuItem("Ajouter une page");
		mi_ajoutPage.addActionListener(this);
		mi_prec=new JMenuItem("Remonter la page");
		mi_prec.addActionListener(this);
		mi_suiv=new JMenuItem("Descendre la page");
		mi_suiv.addActionListener(this);
		mi_copier=new JMenuItem("Copier");
		mi_copier.addActionListener(this);
		mi_coller=new JMenuItem("Coller");
		mi_coller.addActionListener(this);
		mi_couper=new JMenuItem("Couper");
		mi_couper.addActionListener(this);
		mi_renommer=new JMenuItem("Renommer");
		mi_renommer.addActionListener(this);
	
		if (e.getButton() == MouseEvent.BUTTON3) {
			TreePath selPath =getPathForLocation(e.getX(), e.getY()); 
		   if (selPath != null) { 
		      //A partir du chemin, on récupère le noeud 
		      DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent(); 
		      if ((node != null) && (!node.isRoot())) { 
		            setSelectionPath(selPath);
		            if(node.getParent()==dmtn_racine){
		            	popup.add(mi_ajoutPage);
						popup.add(mi_supprimer);
						popup.add(mi_renommer);
						popup.addSeparator();
						popup.add(mi_coller);
						mi_coller.setEnabled(ihm.getControleur().getPressePapier()!=null);
		            }
		            else{
		            	popup.add(mi_ajoutPage);
						popup.add(mi_supprimer);
						popup.addSeparator();
						popup.add(mi_prec);
						popup.add(mi_suiv);
						popup.addSeparator();
						popup.add(mi_couper);
						popup.add(mi_copier);
						mi_prec.setEnabled(ihm.getControleur().getProjetEnCours().getPages().indexOf(ihm.getControleur().getProjetEnCours().getPageEnCours())!=0);
		            	mi_suiv.setEnabled(ihm.getControleur().getProjetEnCours().getPages().indexOf(ihm.getControleur().getProjetEnCours().getPageEnCours())!=ihm.getControleur().getProjetEnCours().getPages().size()-1);
		            }
		      		popup.show(e.getComponent(),e.getX(), e.getY());//affichage du menu sur le composant cliqué
		      } 
		   }
		   else{
				popup2.show(e.getComponent(),e.getX(),e.getY());
		   }
			   
		}
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
	}
	@Override
	public void mouseExited(MouseEvent arg0) {
	}	@Override
	public void mousePressed(MouseEvent arg0) {
	}
	@Override
	public void mouseReleased(MouseEvent arg0) {
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==mi_supprimer){
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
			if(node.getParent()==dmtn_racine)
				supprimer(node.toString());
			else
				supprimer(node.getParent().toString(),node.toString());
		}
		else if(e.getSource()==mi_ajoutPage){
			new FenetreSaisie("Page",ihm);
		}
		else if(e.getSource()==mi_newProjet){
			new FenetreSaisie("Projet",ihm);
		}
		else if(e.getSource()==mi_prec){
			int indice=ihm.getControleur().getProjetEnCours().getPages().indexOf(ihm.getControleur().getProjetEnCours().getPageEnCours());
			ihm.getControleur().getProjetEnCours().getPages().add(indice-1,ihm.getControleur().getProjetEnCours().getPages().remove(indice));
			ihm.majArbre();
		}
		else if(e.getSource()==mi_suiv){
			int indice=ihm.getControleur().getProjetEnCours().getPages().indexOf(ihm.getControleur().getProjetEnCours().getPageEnCours());
			ihm.getControleur().getProjetEnCours().getPages().add(indice+1,ihm.getControleur().getProjetEnCours().getPages().remove(indice));
			ihm.majArbre();
		}
		else if(e.getSource()==mi_copier){
			ihm.getControleur().setPressePapier(SerialClone.clone(ihm.getControleur().getProjetEnCours().getPageEnCours()));
		}
		else if(e.getSource()==mi_couper){
			int indice=ihm.getControleur().getProjetEnCours().getPages().indexOf(ihm.getControleur().getProjetEnCours().getPageEnCours());
			ihm.getControleur().setPressePapier(ihm.getControleur().getProjetEnCours().getPages().remove(indice));
			ihm.majArbre();
			ihm.getVisu().setPage(null);
		}
		else if(e.getSource()==mi_coller){
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
			copieImages();
			copieLien();
			boolean existe=false;
			String titre=ihm.getControleur().getPressePapier().getTitrePage();
			for(Page p:ihm.getControleur().getProjetEnCours().getPages()){
				if(p.getTitrePage().equals(titre))
						existe=true;
			}
			int i=1;
			if(existe){
				if(titre.matches("^.*\\([1-9]\\)$"))
					titre=titre.substring(0,titre.length()-3)+"("+i+")";
				else if(titre.matches("^.*\\([1-9][0-9]\\)$"))
					titre=titre.substring(0,titre.length()-4)+"("+i+")";
				else
					titre=ihm.getControleur().getPressePapier().getTitrePage()+"("+i+")";
				
				ArrayList<Page> alP=ihm.getControleur().getProjetEnCours().getPages();
				for(int j=0;j<alP.size();j++){
					if(alP.get(j).getTitrePage().equals(titre)){
							i++;
							if(i>10)
								titre=titre.substring(0,titre.length()-4)+"("+i+")";
							else
								titre=titre.substring(0,titre.length()-3)+"("+i+")";
							j=0;
					}
				}
			}
			ihm.getControleur().getPressePapier().setTitrePage(titre);
			
			ihm.getControleur().getPressePapier().setProjet(ihm.getControleur().getProjetByNom(node.toString()));
			ihm.getControleur().getProjetEnCours().getPages().add(ihm.getControleur().getPressePapier());
			ihm.getControleur().setPressePapier(null);
			ihm.majArbre();
		}
		else if(e.getSource()==mi_renommer){
			new FenetreSaisie("Renommer un Projet",ihm);
		}
	}
	
	/**
	 * Permet de supprimer un projet
	 * @param nomProjet	nom du projet à supprimer
	 */
	public void supprimer(String nomProjet){
		int res = JOptionPane.showConfirmDialog(ihm, "Supprimer aussi le dossier, ainsi que tout ce qu'il contient, de votre disque dur ?");
		switch(res){
		case JOptionPane.YES_OPTION: if(deleteDir(new File(ihm.getControleur().getRacine()+"/"+nomProjet)))
											JOptionPane.showMessageDialog(null,"Projet supprimé du disque dur");
									 
		case JOptionPane.NO_OPTION:	ihm.getControleur().removeProjetByName(nomProjet);
		 							ihm.majArbre();
		 							ihm.getVisu().setPage(null);
		 							ihm.getMB().activerBoutons(false);
		 							ihm.getMB().activerGenerer(!ihm.getControleur().getProjets().isEmpty());
		 							ihm.getControleur().sauvegarde();
									break;
		}
	}
	
	/**
	 * Permet de supprimer une page d'un projet
	 * @param nomProjet	nom du projet dont la page provient
	 * @param nomPage	nom de la page à supprimer
	 */
	public void supprimer(String nomProjet,String nomPage){
		if(new File(ihm.getControleur().getRacine()+"/"+nomProjet+"/"+ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage).getNomFichier()+".xml").exists())
		{
			int res = JOptionPane.showConfirmDialog(ihm, "Supprimer aussi la page de votre disque dur ?");
			switch(res){
			case JOptionPane.YES_OPTION: suppImages(ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage));
			 							 suppLiens(ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage));
										 if(deleteFile(new File(ihm.getControleur().getRacine()+"/"+nomProjet+"/"+ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage).getNomFichier()+".xml")))
											JOptionPane.showMessageDialog(null,"Page supprimée du disque dur");
										 	
									 
			case JOptionPane.NO_OPTION:	ihm.getControleur().getProjetByNom(nomProjet).removePageByName(nomPage);
		 								ihm.majArbre();
		 								ihm.getVisu().setPage(null);
		 								ihm.getControleur().setProjetEnCours(null);
		 								ihm.getMB().activerBoutons(false);
		 								ihm.getControleur().sauvegarde();
		 								break;
			}
		}
		else{
			suppImages(ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage));
			suppLiens(ihm.getControleur().getProjetByNom(nomProjet).getPageByNom(nomPage));
			ihm.getControleur().getProjetByNom(nomProjet).removePageByName(nomPage);
			ihm.majArbre();
			ihm.getVisu().setPage(null);
			ihm.getMB().activerBoutons(false);
			ihm.getControleur().sauvegarde();
		}
		
	}
	
	/**
	 * Permet de supprimer un dossier
	 * @param dir	dossier à supprimer
	 * @return		vrai(true) si le dossier a été supprimé sinon faux(false)
	 */
	public boolean deleteDir(File dir) {
		//si le fichier est un repertoire il faut le vider avant de le supprimer
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++){
				if(new File(dir+children[i]).isDirectory())
				{
					deleteDir(new File(dir+children[i]));
				}else{
					System.gc();
					File supp= new File(dir, children[i]);
					boolean success =supp.delete();
					if (!success) {
						return false;
					}
						
				}
			}
		}
		
		// le répertoire est vide on peut donc le supprimer
		return dir.delete();
	}
	
	/**
	 * Permet de supprimer un fichier
	 * @param file	fichier à supprimer
	 * @return	vrai(true) si le fichier a été supprimé sinon faux(false)
	 */
	public boolean deleteFile(File file){
		return file.delete();
	}

	/**
	 * Permet de recuperer le niveau du noeud
	 * @return	1 si le noeud est un projet, 2 si le noeud est une page et 0 si le noeud est la racine
	 */
	public int getSelectedNoeud(){
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) getSelectionPath().getLastPathComponent();
		if(node.getParent()==dmtn_racine)
			return 1;
		else if(node.getParent().getParent()==dmtn_racine)
			return 2;
		else
			return 0;
	}
	
	/**
	 * Permet de copier les liens présents sur la page dans le nouveau projet
	 * Renommage automatique si le nom du lien existe déjà dans le dossier ressources
	 */
	public void copieLien(){
		Iterator it=ihm.getControleur().getPressePapier().getChildren("lien").iterator();
		while(it.hasNext()){
			Element e1=(Element) it.next();
			String nomLien=e1.getAttributeValue("lien");
			if(!nomLien.startsWith("http://") && !nomLien.startsWith("https://")){
				File fichier=new File(ihm.getControleur().getRacine()+"/"
									 +ihm.getControleur().getPressePapier().getNomProjet()+"/"
									 +nomLien);
				File sortie=new File(ihm.getControleur().getRacine()+"/"
						 	+ihm.getControleur().getProjetEnCours().getNom()+"/"
						 	+nomLien);
				int i=1;
				
				while(sortie.exists()){
					int index=nomLien.lastIndexOf(".");
					if(index>=0){
						if(nomLien.matches("^.*\\([1-9]\\)\\..*$"))
							nomLien=nomLien.substring(0, index-3)+"("+i+")"+nomLien.substring(index);
						else if(nomLien.matches("^.*\\([1-9][0-9]\\)\\..*$"))
							nomLien=nomLien.substring(0, index-4)+"("+i+")"+nomLien.substring(index);
						else
							nomLien=nomLien.substring(0, index)+"("+i+")"+nomLien.substring(index);
					}
					else{
						if(nomLien.matches("^.*\\([1-9]\\)*$"))
							nomLien=nomLien.substring(0, index-3)+"("+i+")"+nomLien.substring(index);
						else if(nomLien.matches("^.*\\([10-99]\\)*$"))
							nomLien=nomLien.substring(0, index-4)+"("+i+")"+nomLien.substring(index);
						else
							nomLien+="("+i+")";
					}
					sortie=new File(ihm.getControleur().getRacine()+"/"
							 +ihm.getControleur().getProjetEnCours().getNom()+"/"
							 +nomLien);
					i++;
				}
				
				
				if(!sortie.getParentFile().exists())
					sortie.getParentFile().mkdirs();
				
				FileChannel in = null; // canal d'entrée
				FileChannel out = null; // canal de sortie
				 
				try {
				  in = new FileInputStream(fichier).getChannel();
				  out = new FileOutputStream(sortie).getChannel();
				 
				  in.transferTo(0, in.size(), out);
				} catch (Exception ex) {
				  ex.printStackTrace();
				} finally {
				  if(in != null) {
				  	try {
					  in.close();
					} catch (IOException ex) {}
				  }
				  if(out != null) {
				  	try {
					  out.close();
					} catch (IOException ex) {}
				  }
				}
				e1.getAttribute("lien").setValue(nomLien);
			}
		}
	}
	
	/**
	 * Permet de copier les images présentes sur la page dans le nouveau projet
	 * Renommage automatique si le nom de l'image existe déjà dans le dossier images
	 */
	public void copieImages(){
		Iterator it=ihm.getControleur().getPressePapier().getChildren("image").iterator();
		while(it.hasNext()){
			Element e1=(Element) it.next();
			
			String nom=e1.getText();
			File fichier=new File(ihm.getControleur().getRacine()+"/"
								 +ihm.getControleur().getPressePapier().getNomProjet()
								 +"/images/"+e1.getText());
			File sortie=new File(ihm.getControleur().getRacine()+"/"
								 +ihm.getControleur().getProjetEnCours().getNom()
								 +"/images/"+nom);
			int i=1;
			
			while(sortie.exists()){
				int index=nom.lastIndexOf(".");
				if(index>=0){
					if(nom.matches("^.*\\([1-9]\\)\\..*$"))
						nom=nom.substring(0, index-3)+"("+i+")"+nom.substring(index);
					else if(nom.matches("^.*\\([1-9][0-9]\\)\\..*$"))
						nom=nom.substring(0, index-4)+"("+i+")"+nom.substring(index);
					else
					nom=nom.substring(0, index)+"("+i+")"+nom.substring(index);
				}
				else{
					if(nom.matches("^.*\\([1-9]\\)*$"))
						nom=nom.substring(0, index-3)+"("+i+")"+nom.substring(index);
					else if(nom.matches("^.*\\([10-99]\\)*$"))
						nom=nom.substring(0, index-4)+"("+i+")"+nom.substring(index);
					else
						nom+="("+i+")";
				}
				
				sortie=new File(ihm.getControleur().getRacine()+"/"
						 +ihm.getControleur().getProjetEnCours().getNom()
						 +"/images/"+nom);
				i++;
			}
			
			
			if(!sortie.getParentFile().exists())
				sortie.getParentFile().mkdirs();
			
			FileChannel in = null; // canal d'entrée
			FileChannel out = null; // canal de sortie
			 
			try {
			  in = new FileInputStream(fichier).getChannel();
			  out = new FileOutputStream(sortie).getChannel();
			 
			  in.transferTo(0, in.size(), out);
			} catch (Exception ex) {
			  ex.printStackTrace();
			} finally {
			  if(in != null) {
			  	try {
				  in.close();
				} catch (IOException ex) {}
			  }
			  if(out != null) {
			  	try {
				  out.close();
				} catch (IOException ex) {}
			  }
			}
			e1.setText(nom);
		}
	}
	
	public void suppImages(Page p){
		Iterator it=p.getChildren("image").iterator();
		while(it.hasNext()){
			Element elem=(Element)it.next();
			File delImg=new File(ihm.getControleur().getRacine()+"/"+p.getNomProjet()+"/images/"+elem.getText());
			System.gc();
			delImg.delete();
		}
	}
	
	public void suppLiens(Page p){
		Iterator it=p.getChildren("lien").iterator();
		while(it.hasNext()){
			Element elem=(Element)it.next();
			if(!elem.getText().startsWith("http://") && !elem.getText().startsWith("https://")){
				File delFile=new File(ihm.getControleur().getRacine()+"/"+p.getNomProjet()+"/"+elem.getAttributeValue("lien"));
				System.gc();
				delFile.delete();
			}
		}
	}
}
